package fts.ftsdata.services.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;

import fts.ftsdata.domain.impl.Tag;
import fts.ftsdata.domain.impl.TaggedFile;
import fts.ftsdata.services.ILookupService;


public class LookupService implements ILookupService
{
	SessionFactory factory;


	public LookupService(SessionFactory fact)
	{
		factory = fact;
	}

	@SuppressWarnings("unchecked")
	public TaggedFile getFileByName(String str) throws Exception
	{
		System.out.println(Thread.currentThread().getStackTrace()[1]);
		Session sess = factory.openSession();
		TaggedFile res = null;
		try
		{
			Criteria crit = sess.createCriteria(TaggedFile.class).add(Restrictions.ilike("name", str.toLowerCase().replaceAll("\\\\", "\\\\\\\\"), MatchMode.EXACT));
			res = (TaggedFile) crit.uniqueResult();
			return res;
		}
		catch(Exception ex)
		{
			System.out.println(ex);
			throw ex;
		}
		finally
		{
			sess.close();
		}
	}

	@SuppressWarnings("unchecked")
	public Collection<TaggedFile> getFilesByTagExpression(String expression, int pageNum, int pageSize) throws Exception
	{
		System.out.println(Thread.currentThread().getStackTrace()[1]);

		Session sess = factory.openSession();
		ArrayList<TaggedFile> resColl = new ArrayList<TaggedFile>();
		try
		{
			String queryStringFormat = "from TaggedFile file where 1=1 and (%s)";
			String tempExp = "";
			int tagInd = 0;
			ArrayList<Tag> tagList = new ArrayList<Tag>();
			expression = expression == null ? "" : expression.trim();
			if(expression.equals(""))
			{
				tempExp = "1=1";
			}
			else
			{
				String[] ors = expression.split("\\s*\\|\\s*");
				for(String or : ors)
				{

					if(tagInd > 0)
					{
						tempExp += " or ";
					}

					tempExp += "( ";

					String[] ands = or.split("\\s*\\&\\s*");
					int andCnt = 0;
					for(String and : ands)
					{
						String tagStr = and;
						boolean isNot = false;
						if(and.startsWith("!"))
						{
							isNot = true;
							tagStr = and.replaceFirst("!", "");
						}
						Tag tagObj = findTag(tagStr, sess);
						if(tagObj == null)
						{
							throw new Exception("Tag \"" + tagStr + "\" doesn't exist.");
						}
						tagList.add(tagObj);
						if(andCnt > 0)
						{
							tempExp += " and ";
						}
						if(isNot)
						{
							tempExp += "( :tag" + tagInd + "  <> all elements(file.tags) )";
						}
						else
						{
							tempExp += "( :tag" + tagInd + "  = some elements(file.tags) )";
						}
						andCnt++;
						tagInd++;
					}

					tempExp += " )";
				}
			}
			String hqlExpr = String.format(queryStringFormat, tempExp);


			Query quer = sess.createQuery(hqlExpr);

			tagInd = 0;
			for(Tag tagObj : tagList)
			{
				quer.setParameter("tag"+tagInd, tagObj);
				tagInd++;
			}

			quer.setFirstResult(pageNum*pageSize);
			quer.setMaxResults(pageSize);
			List res = quer.list();
			Iterator iter = res.iterator();
			while(iter.hasNext())
			{
				resColl.add((TaggedFile) iter.next());
			}
			sess.flush();
		}
		catch(Exception ex)
		{
			System.out.println(ex);
			throw ex;
		}
		finally
		{
			sess.close();
		}
		return resColl;	

	}
	
	private Tag findTag(String tag, Session sess) throws Exception
	{
		tag = tag.toLowerCase().replaceAll("\\\\", "\\\\\\\\");
		Criteria crit = sess.createCriteria(Tag.class).add(Restrictions.ilike("name", tag, MatchMode.EXACT));
		Object res = crit.uniqueResult();
		return (Tag)res;
	}

	public Tag findTag(String tag) throws Exception
	{
		Tag.assertTagName(tag);
		Tag tagObj = null;
		Session sess = factory.openSession();
		try
		{
			tagObj = findTag(tag, sess);
		}
		catch(Exception ex)
		{
			System.out.println(ex);
		}
		finally
		{
			sess.close();
		}

		return tagObj;
	}

	@SuppressWarnings("unchecked")
	public Collection<Tag> getAllTags() throws Exception
	{
		Session sess = factory.openSession();
		ArrayList<Tag> resColl = new ArrayList<Tag>();
		try
		{
			Criteria crit = sess.createCriteria(Tag.class);
			List res = crit.list();
			Iterator iter = res.iterator();
			while(iter.hasNext())
			{
				resColl.add((Tag) iter.next());
			}
			sess.flush();
		}
		catch(Exception ex)
		{
			System.out.println(ex);
			throw ex;
		}
		finally
		{
			sess.close();
		}
		return resColl;	
	}


}
